﻿using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using NMock2;
using ElectricBillMaker;

namespace ElectricBillMakerTest
{
    [TestFixture]
    public class TModel
    {
        private Mockery mocks_;
        private IModelChangeEvents modelEvents_;
        private IDatabase db_;
        private const float kDefaultAbsError = 0.0001F;

        [SetUp]
        public void Setup()
        {
            mocks_ = new Mockery();
            modelEvents_ = mocks_.NewMock<IModelChangeEvents>();
            db_ = mocks_.NewMock<IDatabase>();
        }

        [Test]
        public void TestConstruction()
        {
            Expect.Never.On(modelEvents_).Method(@"OnCalculated");
            Expect.Never.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay3Change");
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");

            Model model = new Model(modelEvents_, db_);
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay1DeltaGreaterThenPrivilege()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change")
                .With(IsFloat.Near(172.9F, kDefaultAbsError));  // 172.9 = 70 * 2.66 * 0.5 + 30 * 2.66
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change");

            Model model = new Model(modelEvents_, db_);
            model.Tarif1 = 2.66F;
            model.Delta1 = 100;             // 100 kW > 70 kW (PrivilegeKw)
            model.PrivilegePercent = 50; // 50% discount 
            model.PrivilegeKw = 70;      // for 70 kW

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay1DeltaEqualToPrivilege()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change")
                .With(IsFloat.Near(93.1F, kDefaultAbsError));  // 93.1 = 70 * 2.66 * 0.5
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change");

            Model model = new Model(modelEvents_, db_);
            model.Tarif1 = 2.66F;
            model.Delta1 = 70;           // 70 kW == 70 kW (PrivilegeKw)
            model.PrivilegePercent = 50; // 50% discount 
            model.PrivilegeKw = 70;      // for 70 kW

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay1DeltaLessThenPrivilege()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change")
                .With(IsFloat.Near(66.5F, kDefaultAbsError));  // 66.5 = 50 * 2.66 * 0.5
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change");

            Model model = new Model(modelEvents_, db_);
            model.Tarif1 = 2.66F;
            model.Delta1 = 50;           // 50 kW < 70 kW (PrivilegeKw)
            model.PrivilegePercent = 50; // 50% discount 
            model.PrivilegeKw = 70;      // for 70 kW

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay1DeltaIsZero()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change")
                .With(IsFloat.Near(0, kDefaultAbsError));   //  Must be 0
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change");

            Model model = new Model(modelEvents_, db_);
            model.Tarif1 = 2.66F;
            model.Delta1 = 0;           // 0 kW
            model.PrivilegePercent = 50; // 50% discount 
            model.PrivilegeKw = 70;      // for 70 kW

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay2NormalDelta()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change")
                   .With(IsFloat.Near(67.00F, kDefaultAbsError));
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change");

            Model model = new Model(modelEvents_, db_);
            model.Tarif2 = 0.67F;
            model.Delta2 = 100;           

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay2DeltaIsZero()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change")
                   .With(IsFloat.Near(0, kDefaultAbsError));
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change");

            Model model = new Model(modelEvents_, db_);
            model.Tarif2 = 0.67F;
            model.Delta2 = 0;

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay3NormalDelta()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change")
                .With(IsFloat.Near(224.00F, kDefaultAbsError));

            Model model = new Model(modelEvents_, db_);
            model.Tarif3 = 2.24F;
            model.Delta3 = 100;

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CalculateCheckPay3DeltaIsZero()
        {
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");
            Expect.Once.On(modelEvents_).Method(@"OnCalculated");
            Expect.Once.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Once.On(modelEvents_).Method(@"OnToPay3Change")
                .With(IsFloat.Near(0, kDefaultAbsError));

            Model model = new Model(modelEvents_, db_);
            model.Tarif3 = 0.67F;
            model.Delta2 = 0;

            model.Calculate();
            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void MonthYear()
        {
            Expect.Never.On(modelEvents_).Method(@"OnCalculated");
            Expect.Never.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay3Change");
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");

            Model model = new Model(modelEvents_, db_);

            DateTime monthYear = new DateTime(2011, 2, 1);

            model.MonthYear = monthYear;

            Assert.AreEqual(monthYear, model.MonthYear);

            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void CurrentRegistration()
        {
            Expect.Never.On(modelEvents_).Method(@"OnCalculated");
            Expect.Never.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay3Change");
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");

            Model model = new Model(modelEvents_, db_);

            Registration reg = new Registration(new int[3] {2, 4, 6});

            model.CurrentRegistration = reg;

            Assert.AreEqual(reg, model.CurrentRegistration);

            mocks_.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void PreviousRegistration()
        {
            Expect.Never.On(modelEvents_).Method(@"OnCalculated");
            Expect.Never.On(modelEvents_).Method(@"OnToPay1Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay2Change");
            Expect.Never.On(modelEvents_).Method(@"OnToPay3Change");
            Expect.Never.On(db_).Method(@"AddRegistration");
            Expect.Never.On(db_).Method(@"SubmitChanges");

            Model model = new Model(modelEvents_, db_);

            Registration reg = new Registration(new int[3] { 2, 4, 6 });

            model.PreviousRegistration = reg;

            Assert.AreEqual(reg, model.PreviousRegistration);

            mocks_.VerifyAllExpectationsHaveBeenMet();
        }
    }
}
